package com.cdck.safe.dete.controller;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cdck.safe.dete.common.enums.RecordFinishedEnum;
import com.cdck.safe.dete.common.result.Result;
import com.cdck.safe.dete.common.util.SecurityUtils;
import com.cdck.safe.dete.model.entity.CheckProject;
import com.cdck.safe.dete.model.entity.CheckRecord;
import com.cdck.safe.dete.model.entity.SysDept;
import com.cdck.safe.dete.model.entity.SysUser;
import com.cdck.safe.dete.model.vo.*;
import com.cdck.safe.dete.security.userdetails.SysUserDetails;
import com.cdck.safe.dete.service.CheckProjectService;
import com.cdck.safe.dete.service.CheckRecordService;
import com.cdck.safe.dete.service.SysDeptService;
import com.cdck.safe.dete.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.time.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xwj
 * @description 客户端控制
 * @Date 2024/2/29 下午 5:14
 */
@RestController
@RequestMapping("queue")
@RequiredArgsConstructor
public class QueueController {

    /*
      1、需要科室编号信息和用户排队信息，即用户列表
      2、每一个项目的排队人数，
      3、查每一个科室下面排队人数和预排队时间
      4、新增，根据科室id，向redis末尾添加一条数据（传参：科室id，用户id）
      5、交换插队逻辑：老科室id，新科室id：如果是同一个二级科室id，就是插队，更换位置，如果是不同科室id，则还需要删除原先科室id的元素，去新的科室排队信息添加。
      传四个参数，（分别是新旧科室的id，用户的id，具体位置的索引），如果新旧科室id一样，则是插队，直接将原来位置的元素删除，重新插入到指定位置。
      6、根据科室id，用户id，删除指定元素，取消某人排队
     */

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CheckRecordService recordService;

    @Autowired
    private CheckProjectService projectService;

    @Autowired
    private SysDeptService deptService;

    @Autowired
    private SysUserService userService;

    /**
     * 在排队的项目key
     */
    private static final String QUEUE_LIST = "queue:list:";
    /**
     * 用户待检查的项目key
     */
    private static final String USER_CHECK = "queue:unChecking:";


    /**
     * 分配用户套餐
     */
    @PostMapping("/assign")
    public Result<String> assignProjectToUser() {
        Long userId = SecurityUtils.getUserId();
        List<CheckProject> checkProjects = projectService.queryAllProject();
        checkProjects.forEach(e -> {
            CheckRecord checkRecord = new CheckRecord();
            checkRecord.setProjectId(e.getId());
            checkRecord.setUserId(userId);
            recordService.saveCheckRecord(checkRecord);
        });

        return Result.success();
    }

    /**
     * 返回推荐的项目
     *
     * @return
     */
    @PostMapping("/recommend")
    public Result<CheckProjectVO> recommend() {
        //当前登录用户的id
        Long userId = SecurityUtils.getUserId();
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();

        LambdaQueryWrapper<CheckRecord> recordQueryWrapper = new LambdaQueryWrapper<>();
        LocalDate currentDate = LocalDate.now();
        LocalDateTime startOfDay = LocalDateTime.of(currentDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);
        //只要今天未检测完成的记录
        recordQueryWrapper.eq(CheckRecord::getUserId, userId)
                .ge(CheckRecord::getCreateTime, startOfDay)
                .le(CheckRecord::getCreateTime, endOfDay)
                .eq(CheckRecord::getFinished, RecordFinishedEnum.UN_FINISHED.getValue());
        List<CheckRecord> recordList = recordService.list(recordQueryWrapper);
        List<Long> projectIds = recordList.stream().map(item -> item.getProjectId()).collect(Collectors.toList());

        List<CheckProject> projectList = new ArrayList<>();
        if (projectIds.size() > 0) {
            projectList = projectService.listByIds(projectIds);
        }

        List<CheckProjectVO> projectVOList = BeanUtil.copyToList(projectList, CheckProjectVO.class);
        Double resultDuration = 0d;
        CheckProjectVO result = new CheckProjectVO();

        projectVOList.stream().forEach(checkProjectVO -> {
            //获取科室信息
            LambdaQueryWrapper<SysDept> deptQueryWrapper = new LambdaQueryWrapper<>();
            deptQueryWrapper.eq(SysDept::getParentId, checkProjectVO.getDeptId());
            List<SysDept> deptList = deptService.list(deptQueryWrapper);
            List<SysDeptVO> sysDeptVOList = BeanUtil.copyToList(deptList, SysDeptVO.class);
            sysDeptVOList.stream().forEach(sysDeptVO -> {
                //获取科室下面排队人数
                String key = QUEUE_LIST + sysDeptVO.getId();
                Long size = opsForList.size(key);
                Double projectDuration = checkProjectVO.getDuration();

                if (size * projectDuration > resultDuration) {
                    //如果当前排队人数*项目时长大于当前已排队时长，则将当前项目添加到当前科室的排队列表中
                    BeanUtil.copyProperties(checkProjectVO, result);
                    result.setDuration(resultDuration);
                    result.setSysDeptVO(sysDeptVO);
                } else if (size * projectDuration == resultDuration) {
                    //比较优先级
                    if (checkProjectVO.getPriority() > result.getPriority()) {
                        //如果当前项目优先级大于当前排队时长的项目，则将当前项目添加到当前科室的排队列表中
                        BeanUtil.copyProperties(checkProjectVO, result);
                        result.setDuration(resultDuration);
                        result.setSysDeptVO(sysDeptVO);
                    }
                }
            });
        });
        return Result.success(result);
    }

    /**
     * 查询每个项目对应的科室，以及每个科室的排队人数
     *
     * @return Result
     * @author Sakura
     */
    @GetMapping("/project")
    public Result projectList(@RequestParam(value = "userId", required = false) Long userId) {
        if (userId == null) {
            //当前登录用户的id
            userId = SecurityUtils.getUserId();
        }
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();

        LambdaQueryWrapper<CheckRecord> recordQueryWrapper = new LambdaQueryWrapper<>();
        LocalDate currentDate = LocalDate.now();
        LocalDateTime startOfDay = LocalDateTime.of(currentDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);
        //只要今天未检测完成的记录
        recordQueryWrapper.eq(CheckRecord::getUserId, userId)
                .ge(CheckRecord::getCreateTime, startOfDay)
                .le(CheckRecord::getCreateTime, endOfDay);
        List<CheckRecord> recordList = recordService.list(recordQueryWrapper);
        List<Long> projectIds = recordList.stream().map(item -> item.getProjectId()).collect(Collectors.toList());

        List<CheckProject> projectList = new ArrayList<>();
        if (projectIds.size() > 0) {
            projectList = projectService.listByIds(projectIds);
        }

        List<CheckProjectVO> projectVOList = BeanUtil.copyToList(projectList, CheckProjectVO.class);

        List<CheckProjectVO> collect = projectVOList.stream().peek(checkProjectVO -> {
            LambdaQueryWrapper<SysDept> deptQueryWrapper = new LambdaQueryWrapper<>();
            deptQueryWrapper.eq(SysDept::getParentId, checkProjectVO.getDeptId());
            List<SysDept> deptList = deptService.list(deptQueryWrapper);
            List<SysDeptVO> sysDeptVOList = BeanUtil.copyToList(deptList, SysDeptVO.class);
            List<SysDeptVO> collectDept = sysDeptVOList.stream().peek(sysDeptVO -> {
                String key = QUEUE_LIST + sysDeptVO.getId();
                List<String> userIds = opsForList.range(key, 0, -1);
                if (userIds.size() > 0) {
                    List<SysUser> userList = userService.listByIds(userIds);
                    sysDeptVO.setUserList(userList);
                }
            }).collect(Collectors.toList());
            Optional<CheckRecord> first = recordList.stream().filter(e -> e.getProjectId().equals(checkProjectVO.getId())).findFirst();
            first.ifPresent(e -> {
                checkProjectVO.setFinished(e.getFinished());
                checkProjectVO.setQueueingDeptId(e.getDeptId());
                checkProjectVO.setDocId(e.getDocId());
                checkProjectVO.setDocName(e.getDocName());
            });
            checkProjectVO.setDeptList(collectDept);
        }).collect(Collectors.toList());

        return Result.success(collect);
    }


    /**
     * 查询科室列表以及科室下的排队人员列表
     *
     * @return Result
     * @author Sakura
     */
    @GetMapping("/dept")
    public Result deptUserList() {
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        LambdaQueryWrapper<SysDept> deptQueryWrapper = new LambdaQueryWrapper<SysDept>();
        deptQueryWrapper.gt(SysDept::getParentId, 0);
        //子科室
        List<SysDept> deptList = deptService.list(deptQueryWrapper);
        List<QueueDeptVO> voList = BeanUtil.copyToList(deptList, QueueDeptVO.class);
        voList.forEach(item -> {
            String key = USER_CHECK + item.getId();
            //去缓存查询对应的用户
            List<String> userIds = opsForList.range(key, 0, -1);
            if (userIds.size() >= 0) {
                List<SysUser> userList = userService.listByIds(userIds);
                item.setUsers(userList);
            }
        });
        return Result.success(voList);
    }

    /**
     * 某个项目排队人数
     *
     * @param projectId:
     * @return Result
     * @author Sakura
     * @date 2024/3/10 11:52
     */
    @GetMapping("/single/detail")
    public Result queueDeptDetail(@RequestParam Long projectId) {
        Long aLong = queryProjectQueueNumber(projectId);
        return Result.success(aLong);
    }

    public Long queryProjectQueueNumber(Long projectId) {
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        CheckProject project = projectService.getById(projectId);
        //顶级部门
        SysDept sysDept = deptService.getById(project.getDeptId());

        //子部门
        LambdaQueryWrapper<SysDept> deptQueryWrapper = new LambdaQueryWrapper<SysDept>();
        deptQueryWrapper.eq(SysDept::getParentId, sysDept.getId());
        List<SysDept> deptList = deptService.list(deptQueryWrapper);
        List<Long> deptIds = deptList.stream().map(item -> item.getId()).collect(Collectors.toList());
        Long totalNum = 0l;
        for (Long deptId : deptIds) {
            String key = QUEUE_LIST + deptId;
            totalNum += opsForList.size(key);
        }
        Map<String, Object> map = new HashMap<>();
        return totalNum;
    }


    /**
     * 医生负责的科室排队人数
     *
     * @param
     * @return
     * @author wp
     * @date 2024/3/12 20:56
     */
    @GetMapping("/doctor/dept/users")
    public Result queueDeptDetailByDoctor() {
        // 获取当前医生负责的科室Id
        Long deptId = SecurityUtils.getDeptId();

        Map<String, Object> map = new HashMap<>();
        if (!Objects.equals(deptId, null)) {
            // 查询科室名称
            SysDept deptInfo = deptService.getById(deptId);
            // 根据科室Id获取科室下排队人员 信息
            List<String> userIs = stringRedisTemplate.opsForList().range(QUEUE_LIST + deptId, 0, -1);
            // userId 获取用户信息
            if (userIs.size() == 0) {
                map.put("deptInfo", deptInfo);
                return Result.success(map);
            }
            // 使用批量 会对数据重排序
            List<SysUser> userList = new ArrayList<>();
            for (String id : userIs) {
                userList.add(userService.getById(id));
            }
            List<UserVo> userVos = userList.stream().map(item -> {
                UserVo userVo = new UserVo();
                BeanUtil.copyProperties(item, userVo);
                return userVo;
            }).collect(Collectors.toList());

            map.put("deptInfo", deptInfo);
            map.put("userList", userVos);
            return Result.success(map);
        } else {
            throw new RuntimeException("当前医生没有绑定科室");
        }
    }

    /**
     * 医生负责的科室和同级科室排队情况
     *
     * @param
     * @return
     * @author wp
     * @date 2024/3/12 20:56
     */
    @GetMapping("/doctor/deptORSibling/users")
    public Result queueDeptORSiblingByDoctor() {

        Long deptId = SecurityUtils.getDeptId();
        if (Objects.equals(deptId, null)) {
            throw new RuntimeException("当前医生没有绑定科室");
        }
        SysDept deptInfo = deptService.getById(SecurityUtils.getDeptId());
        Long parentId = deptInfo.getParentId();
        List<Map> list = new ArrayList<>();
        List<SysDept> deptList = deptService.list(new LambdaQueryWrapper<SysDept>().eq(SysDept::getParentId, parentId));
        if (deptList.size() > 0) {
            for (SysDept dept : deptList) {
                HashMap<String, Object> map = new HashMap<>();
                // 根据科室Id获取科室下排队人员 信息
                List<String> userIs = stringRedisTemplate.opsForList().range(QUEUE_LIST + dept.getId(), 0, -1);
                // userId 获取用户信息
                // 使用批量 会对数据重排序
                if (userIs.size() > 0) {
                    List<SysUser> userList = new ArrayList<>();
                    for (String id : userIs) {
                        userList.add(userService.getById(id));
                    }
                    List<UserVo> userVos = userList.stream().map(item -> {
                        UserVo userVo = new UserVo();
                        BeanUtil.copyProperties(item, userVo);
                        return userVo;
                    }).collect(Collectors.toList());

                    map.put("userList", userVos);
                } else {
                    map.put("userList", new ArrayList<>());
                }
                map.put("deptInfo", dept);
                list.add(map);
            }
        }
        return Result.success(list);
    }


    /**
     * 根据科室Id查询 同级科室排队信息
     *
     * @param
     * @return
     * @author wp
     * @date 2024/3/12 20:56
     */
    @GetMapping("/doctor/deptORSibling/users/{deptId}")
    public Result queueDeptORSiblingByDeptID(@PathVariable("deptId") Integer deptId) {

        SysDept deptInfo = deptService.getById(deptId);
        Long parentId = deptInfo.getParentId();
        List<Map> list = new ArrayList<>();
        List<SysDept> deptList = deptService.list(new LambdaQueryWrapper<SysDept>().eq(SysDept::getParentId, parentId));
        if (deptList.size() > 0) {
            for (SysDept dept : deptList) {
                HashMap<String, Object> map = new HashMap<>();
                // 根据科室Id获取科室下排队人员 信息
                List<String> userIs = stringRedisTemplate.opsForList().range(QUEUE_LIST + dept.getId(), 0, -1);
                // userId 获取用户信息
                // 使用批量 会对数据重排序
                if (userIs.size() > 0) {
                    List<SysUser> userList = new ArrayList<>();
                    for (String id : userIs) {
                        userList.add(userService.getById(id));
                    }
                    List<UserVo> userVos = userList.stream().map(item -> {
                        UserVo userVo = new UserVo();
                        BeanUtil.copyProperties(item, userVo);
                        return userVo;
                    }).collect(Collectors.toList());

                    map.put("userList", userVos);
                } else {
                    map.put("userList", new ArrayList<>());
                }
                map.put("deptInfo", dept);
                list.add(map);
            }
        }
        return Result.success(list);
    }

    /**
     * 每个科室排队人数和等待时间
     *
     * @param :
     * @return Result
     * @author Sakura
     * @date 2024/3/10 11:51
     */
    @GetMapping("/dept/duration")
    public Result queueDuration(@RequestParam Long deptId) {
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        SysDept sysDept = deptService.getById(deptId);
        DeptQueueDurationVO deptVo = new DeptQueueDurationVO();
        BeanUtil.copyProperties(sysDept, deptVo);
        String key = QUEUE_LIST + deptId;
        Long userNum = opsForList.size(key);
        if (userNum > 0) {
            deptVo.setUserNum(userNum);
            //父级部门id
            Long parentDeptId = sysDept.getParentId();
            LambdaQueryWrapper<CheckProject> checkProjectQuery = new LambdaQueryWrapper<>();
            checkProjectQuery.eq(CheckProject::getDeptId, parentDeptId);
            CheckProject checkProject = projectService.getOne(checkProjectQuery);
            Double projectDuration = checkProject.getDuration();
            deptVo.setQueueDuration(projectDuration * userNum);
        }
        return Result.success(deptVo);
    }

    @GetMapping("/dept/queryAllProjectQueue")
    public Result<List<CheckProject>> queryAllProjectQueue() {
        LocalDate currentDate = LocalDate.now();
        LocalDateTime startOfDay = LocalDateTime.of(currentDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);
        List<CheckRecord> recordList = recordService.list(new LambdaQueryWrapper<CheckRecord>().ge(CheckRecord::getCreateTime, startOfDay)
                .le(CheckRecord::getCreateTime, endOfDay));
        List<CheckProject> list = projectService.list();
        List<CheckProject> collect = list.stream().peek(project -> {
            long finished = recordList.stream().filter(e -> e.getFinished().equals(RecordFinishedEnum.FINISHED.getValue()) && e.getProjectId().equals(project.getId())).count();
            long unFinished = recordList.stream().filter(e -> e.getFinished().equals(RecordFinishedEnum.UN_FINISHED.getValue()) && e.getProjectId().equals(project.getId())).count();
            Long aLong = queryProjectQueueNumber(project.getId());
            project.setNumber(aLong);
            project.setUnFinished(unFinished);
            project.setFinished(finished);
        }).collect(Collectors.toList());
        return Result.success(collect);
    }

    /**
     * 新增排队人员
     *
     * @param :
     * @return Result
     * @author Sakura
     * @date 2024/3/10 11:51
     */
    @GetMapping("/add")
    public Result add(@RequestParam Long userId, @RequestParam Long deptId) {
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        String key = QUEUE_LIST + deptId;
        List<String> range = opsForList.range(key, 0, -1);
        if (range.contains(String.valueOf(userId))) {
            return Result.failed("该用户已经在该队列中");
        }
        //不存在则直接存储
        opsForList.rightPush(key, String.valueOf(userId));
        CheckRecord checkRecord = getCheckRecord(userId, deptId);
        checkRecord.setFinished(RecordFinishedEnum.QUEUEING.getValue());
        recordService.updateById(checkRecord);
        return Result.success(true);
    }


    /**
     * 医生取消某人排队
     *
     * @param :
     * @return Result
     * @author Sakura
     * @date 2024/3/10 11:51
     */
    @GetMapping("/cancel")
    public Result cancel(@RequestParam Long userId, @RequestParam Long deptId) {
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        String key = QUEUE_LIST + deptId;
        CheckRecord checkRecord = getCheckRecord(userId, deptId);
        if (checkRecord == null) {
            throw new RuntimeException("该用户没有排队记录");
        }
        checkRecord.setFinished(RecordFinishedEnum.UN_FINISHED.getValue());
        boolean update = recordService.updateById(checkRecord);
        //直接取消排队
        Long remove = opsForList.remove(key, 0, String.valueOf(userId));
        if (remove > 0) {
            return Result.success("取消成功");
        }
        return Result.failed("该用户不在队列中");
    }

    /**
     * 某人取消自己的排队
     *
     * @param :
     * @return Result
     * @author Sakura
     * @date 2024/3/10 11:51
     */
    @GetMapping("/user/cancel")
    public Result cancel(@RequestParam Long projectId) {
        Long userId = SecurityUtils.getUserId();
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        CheckProject checkProject = projectService.getById(projectId);
        Long deptId = checkProject.getDeptId();
        LambdaQueryWrapper<SysDept> deptQueryWrapper = new LambdaQueryWrapper<SysDept>()
                .eq(SysDept::getParentId, deptId);
        List<SysDept> sysDeptList = deptService.list(deptQueryWrapper);
        if (sysDeptList.size() > 0) {
            for (SysDept sysDept : sysDeptList) {
                String key = QUEUE_LIST + sysDept.getId();
                List<String> range = opsForList.range(key, 0, -1);
                if (range.contains(String.valueOf(userId))) {
                    CheckRecord checkRecord = getCheckRecord(userId, sysDept.getId());
                    if (checkRecord == null) {
                        throw new RuntimeException("该用户没有排队记录");
                    }
                    checkRecord.setFinished(RecordFinishedEnum.UN_FINISHED.getValue());
                    boolean update = recordService.saveOrUpdate(checkRecord,
                            new LambdaUpdateWrapper<CheckRecord>()
                                    .eq(CheckRecord::getId, checkRecord.getId())
                                    .set(CheckRecord::getDeptId, null));
                    //直接取消排队
                    Long remove = opsForList.remove(key, 0, String.valueOf(userId));
                    if (remove > 0) {
                        return Result.success("取消成功");
                    }
                }
            }
        }
        return Result.failed("该用户不在队列中");
    }

    /**
     * 医生点击确认
     *
     * @param :
     * @return Result
     * @author Sakura
     * @date 2024/3/10 11:51
     */
    @Transactional
    @GetMapping("/finished")
    public Result finished(@RequestParam Long userId, @RequestParam Long deptId) {
        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        String key = QUEUE_LIST + deptId;
        SysUserDetails user = SecurityUtils.getUser();
        Long docId = user.getUserId();
        String dcoName = user.getUsername();
        CheckRecord checkRecord = getCheckRecord(userId, deptId);
        checkRecord.setFinished(RecordFinishedEnum.FINISHED.getValue());
        checkRecord.setDocId(docId);
        checkRecord.setDocName(dcoName);
        checkRecord.setEndTime(LocalDateTime.now());
        boolean update = recordService.updateById(checkRecord);

        //把某人从队列中移除
        Long remove = opsForList.remove(key, 0, String.valueOf(userId));
        if (remove > 0) {
            return Result.success("完成");
        }
        return Result.failed("该用户不在队列中");
    }

    private CheckRecord getCheckRecord(Long userId, Long deptId) {
        SysDept sysDept = deptService.getById(deptId);
        Long sysDeptParentId = sysDept.getParentId();
        SysDept sysDeptParent = deptService.getById(sysDeptParentId);
        Long parentId = sysDeptParent.getId();
        LambdaQueryWrapper<CheckProject> projectQuery = new LambdaQueryWrapper<>();
        projectQuery.eq(CheckProject::getDeptId, parentId);
        CheckProject checkProject = projectService.getOne(projectQuery);

        LocalDate currentDate = LocalDate.now();
        LocalDateTime startOfDay = LocalDateTime.of(currentDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);

        LambdaQueryWrapper<CheckRecord> checkRecordQuery = new LambdaQueryWrapper<>();
        checkRecordQuery.eq(CheckRecord::getUserId, userId)
                .eq(CheckRecord::getProjectId, checkProject.getId())
                .ge(CheckRecord::getCreateTime, startOfDay)
                .le(CheckRecord::getCreateTime, endOfDay);

        CheckRecord checkRecord = recordService.getOne(checkRecordQuery);
        return checkRecord;
    }


    /**
     * 用户点击排队
     *
     * @param :
     * @return Result
     * @author Sakura
     * @date 2024/3/10 11:51
     */
    @GetMapping("/rank")
    public Result rank(@RequestParam Long deptId, @RequestParam(value = "userId", required = false) Long userId) {
        if (userId == null) {
            userId = SecurityUtils.getUserId();
        }
        LocalDate currentDate = LocalDate.now();
        LocalDateTime startOfDay = LocalDateTime.of(currentDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);

        ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
        String key = QUEUE_LIST + deptId;
        List<String> range = opsForList.range(key, 0, -1);
        if (range.contains(String.valueOf(userId))) {
            return Result.failed("该用户已经在该队列中");
        }

        LambdaQueryWrapper<CheckRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CheckRecord::getUserId, userId)
                .eq(CheckRecord::getFinished, RecordFinishedEnum.QUEUEING.getValue())
                .ge(CheckRecord::getCreateTime, startOfDay)
                .le(CheckRecord::getCreateTime, endOfDay);
        long count = recordService.count(wrapper);
        if (count > 0) return Result.failed("请完成当前正在排队的项目!");

        CheckRecord checkRecord = getCheckRecord(userId, deptId);
        checkRecord.setFinished(RecordFinishedEnum.QUEUEING.getValue());
        checkRecord.setDeptId(deptId);
        recordService.updateById(checkRecord);
        //不存在则直接存储
        Long leftPush = opsForList.rightPush(key, String.valueOf(userId));
        return Result.success(leftPush > 0);
    }


    /**
     * 插队
     *
     * @param currentDeptId:
     * @param targetDeptId:
     * @param currentUserId:
     * @param targetUserId:
     * @return Result
     * @author Sakura
     * @date 2024/3/10 13:10
     */
    @GetMapping("/insert")
    public Result exchange(@RequestParam Long currentDeptId,
                           @RequestParam Long targetDeptId,
                           @RequestParam Long currentUserId,
                           @RequestParam(required = false) Long targetUserId) {
        if (Objects.equals(currentUserId, targetUserId)) {
            throw new RuntimeException("不能选择插自己");
        }

        String key = QUEUE_LIST + targetDeptId;
        ListOperations<String, String> opsList = stringRedisTemplate.opsForList();

        if (Objects.equals(currentDeptId, targetDeptId)) {
            // 同科室插队
            opsList.remove(key, 0, String.valueOf(currentUserId));
        } else {
            // 跨科室插队
            opsList.remove(QUEUE_LIST + currentDeptId, 0, String.valueOf(currentUserId));
        }

        if (Objects.equals(targetUserId, null)) {
            opsList.rightPush(key, String.valueOf(currentUserId));
        } else {
            opsList.leftPush(key, String.valueOf(targetUserId), String.valueOf(currentUserId));
        }

        // 修改对应DB记录
        LocalDate currentDate = LocalDate.now();
        LocalDateTime startOfDay = LocalDateTime.of(currentDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);
        CheckRecord record = recordService.getOne(new LambdaQueryWrapper<CheckRecord>()
                .eq(CheckRecord::getUserId, currentUserId)
                .eq(CheckRecord::getDeptId, currentDeptId)
                .eq(CheckRecord::getFinished, RecordFinishedEnum.QUEUEING.getValue())
                .ge(CheckRecord::getCreateTime, startOfDay)
                .le(CheckRecord::getCreateTime, endOfDay)
        );
        record.setDeptId(targetDeptId);
        recordService.updateById(record);

        return Result.success(true);
    }

    @GetMapping("/getDashboardData")
    public Result<Object> getDashboardData() {
        Map<String, Object> dashboard = new HashMap<>();
        LocalDate currentDate = LocalDate.now();
        LocalDateTime startOfDay = LocalDateTime.of(currentDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);
        List<CheckRecord> list = recordService.list(new LambdaQueryWrapper<CheckRecord>().ge(CheckRecord::getCreateTime, startOfDay)
                .le(CheckRecord::getCreateTime, endOfDay));
        long unFinish = list.stream().filter(e -> e.getFinished().equals(RecordFinishedEnum.UN_FINISHED.getValue())).map(CheckRecord::getUserId).count();
        long queueing = list.stream().filter(e -> e.getFinished().equals(RecordFinishedEnum.QUEUEING.getValue())).map(CheckRecord::getUserId).count();
        long finished = list.stream().filter(e -> e.getFinished().equals(RecordFinishedEnum.FINISHED.getValue())).map(CheckRecord::getUserId).count();
        Set<Long> collect = list.stream().map(CheckRecord::getUserId).collect(Collectors.toSet());
        dashboard.put("projectNumber", projectService.count());
        dashboard.put("userNumber", collect.size());
        dashboard.put("unFinish", unFinish);
        dashboard.put("queueing", queueing);
        dashboard.put("finished", finished);
        return Result.success(dashboard);
    }

    /**
     * 获取所有科室和科室的排队人数
     *
     * @param
     * @return
     * @author xwj
     * @date 2024/3/23 22:49
     */
    @GetMapping("/all/queues")
    public Result<Object> getAllQueueList() {
        Set<String> keys = stringRedisTemplate.keys(QUEUE_LIST + "*");
        List<Map<String, Object>> data = new ArrayList<>();
        keys.stream().forEach(item -> {
            Map map = new HashMap<>();
            Integer deptId = Integer.parseInt(item.substring(item.lastIndexOf(":") + 1));
            SysDept dept = deptService.getById(deptId);
            if (dept != null) {
                map.put("deptName", dept.getName());
            } else {
                map.put("deptName", null);
            }
            map.put("deptId", deptId);
            Long size = stringRedisTemplate.opsForList().size(item);
            map.put("num", size);
            data.add(map);
        });
        return Result.success(data);
    }

    /**
     * 根据科室Id 获取科室下的排队详情
     *
     * @param
     * @return
     * @author xwj
     * @date 2024/3/23 22:49
     */
    @GetMapping("/{deptId}/queueDetail")
    public Result<Object> getDeptQueueList(@PathVariable Long deptId) {

        Map<String, Object> map = new HashMap<>();
        // 查询科室名称
        SysDept deptInfo = deptService.getById(deptId);
        // 根据科室Id获取科室下排队人员 信息
        List<String> userIs = stringRedisTemplate.opsForList().range(QUEUE_LIST + deptId, 0, -1);
        // userId 获取用户信息
        if (userIs.size() == 0) {
            map.put("deptInfo", deptInfo);
            return Result.success(map);
        }
        // 使用批量 会对数据重排序
        List<SysUser> userList = new ArrayList<>();
        for (String id : userIs) {
            userList.add(userService.getById(id));
        }
        List<UserVo> userVos = userList.stream().map(item -> {
            UserVo userVo = new UserVo();
            BeanUtil.copyProperties(item, userVo);
            return userVo;
        }).collect(Collectors.toList());

        map.put("deptInfo", deptInfo);
        map.put("userList", userVos);
        return Result.success(map);
    }

    /**
     * 获取病人待检测项目信息
     */
    @GetMapping("/await/queueUsers")
    public Result<List<AwaitQueueDetailVo>> awaitQueueUserList() {
        List<AwaitQueueDetailVo> data = new ArrayList<>();
        // 获取今日排队列表
        LocalDate currentDate = LocalDate.now();
        LocalDateTime startOfDay = LocalDateTime.of(currentDate, LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(currentDate, LocalTime.MAX);
        List<CheckRecord> list = recordService.list(new LambdaQueryWrapper<CheckRecord>().ge(CheckRecord::getCreateTime, startOfDay)
                .le(CheckRecord::getCreateTime, endOfDay));
        // 获取项目列表
        List<CheckProject> checkProjects = projectService.list();
        Map<Long, String> checkProjectNameMap = checkProjects.stream().collect(Collectors.toMap(CheckProject::getId, CheckProject::getName));
        // 按照userId分组
        Map<Long, List<CheckRecord>> listMap = list.stream().collect(Collectors.groupingBy(CheckRecord::getUserId));
        // 获取正在排队的所有id
        Set<String> keys = redisTemplate.keys(QUEUE_LIST+'*');
        ListOperations listOperations = redisTemplate.opsForList();
        Set<Long> queueIds = new HashSet<>();
        for (String key : keys) {
            List<Integer> range = listOperations.range(key, 0, -1);
            for (Integer id : range) {
                queueIds.add(Long.valueOf(id));
            }
        }
        for (Long key : listMap.keySet()) {
            List<CheckRecord> checkRecords = listMap.get(key);
            List<CheckRecord> unFinishCheck = checkRecords.stream().filter(item -> item.getFinished() == 0).collect(Collectors.toList());
            if (unFinishCheck.size() > 0) {
                AwaitQueueDetailVo awaitQueueDetailVo = new AwaitQueueDetailVo();
                awaitQueueDetailVo.setUserId(key);
                awaitQueueDetailVo.setQueuing(queueIds.contains(key));
                awaitQueueDetailVo.setUserName(userService.getById(key).getNickname());
                List<CheckProject> unFinishRro = unFinishCheck.stream().map(pro -> {
                    CheckProject checkProject = new CheckProject();
                    checkProject.setId(pro.getProjectId());
                    checkProject.setName(checkProjectNameMap.get(pro.getProjectId()));
                    return checkProject;
                }).collect(Collectors.toList());
                awaitQueueDetailVo.setAwaitingProjects(unFinishRro);
                data.add(awaitQueueDetailVo);
            }
        }
        return Result.success(data);
    }

}
